package com.atguigu.lease.web.app.service.impl;

import com.atguigu.lease.common.constant.RedisConstant;
import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.utils.CodeUtil;
import com.atguigu.lease.common.utils.JwtUtil;
import com.atguigu.lease.model.entity.UserInfo;
import com.atguigu.lease.model.enums.BaseStatus;
import com.atguigu.lease.web.app.mapper.UserInfoMapper;
import com.atguigu.lease.web.app.service.LoginService;
import com.atguigu.lease.web.app.service.SmsService;
import com.atguigu.lease.web.app.vo.user.LoginVo;
import com.atguigu.lease.web.app.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

	@Autowired
	private SmsService smsService;

	@Autowired
	private StringRedisTemplate redisTemplate;

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Override
	public void getCode(String phone) {
		// 生成一个长度为6的随机数字字符串作为验证码
		String randomCode = CodeUtil.getRandomCode(6);
		// 通过拼接来构建一个唯一的Redis键名
		String key = RedisConstant.APP_LOGIN_PREFIX + phone;

		// 检查Redis中是否存在该Key
		Boolean hasKey = redisTemplate.hasKey(key);
		if (hasKey) {
			// 如果存在，则获取该Key的TTL（Time to Live），即剩余的有效时间
			Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
			// 根据计算结果判断是否可以再次发送验证码，用来限制用户在短时间内重复请求验证码的频率
			if (RedisConstant.APP_LOGIN_CODE_TTL_SEC - ttl<RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC){
				throw new LeaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
			}
		}

		// 发送短信验证码
		smsService.sendCode(phone, randomCode);
		// 存储验证码到Redis
		redisTemplate.opsForValue().set(key,randomCode,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);

	}

	@Override
	public String login(LoginVo loginVo) {
		// 首先校验`phone`和`code`是否为空，若为空，直接响应`手机号码为空`或者`验证码为空`，若不为空则进入下步判断
		if (loginVo.getPhone() == null) {
			throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
		}
		if (loginVo.getCode() == null) {
			throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
		}

		// 根据 phone 从Redis中查询之前保存的验证码，若查询结果为空，则直接响应 验证码已过期 ，若不为空则进入下一步判断
		String key = RedisConstant.APP_LOGIN_PREFIX + loginVo.getPhone();
		String code = redisTemplate.opsForValue().get(key);
		if (code == null) {
			throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
		}

		// 比较前端发送的验证码和从Redis中查询出的验证码，若不同，则直接响应验证码错误，若相同则进入下一步判断。
		if (!code.equals(loginVo.getCode())) {
			throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
		}

		// 使用 phone 从数据库中查询用户信息，若查询结果为空，则创建新用户，并将用户保存至数据库，然后进入下一步判断。
		LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserInfo::getPhone, loginVo.getPhone());
		UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
		if (userInfo == null) {
			// 注册
			userInfo = new UserInfo();
			userInfo.setPhone(loginVo.getPhone());
			userInfo.setStatus(BaseStatus.ENABLE);
			userInfo.setNickname("用户-" + loginVo.getPhone().substring(7));
			userInfoMapper.insert(userInfo);
		} else {
			// 判断用户是否被禁用，若被禁，则直接响应账号被禁用，否则进入下一步。
			if (userInfo.getStatus() == BaseStatus.DISABLE) {
				throw new LeaseException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
			}
		}

		// 创建JWT并响应给前端。
		return JwtUtil.createToken(userInfo.getId(), userInfo.getPhone());
	}

	@Override
	public UserInfoVo getLoginUserById(Long userId) {
		UserInfo userInfo = userInfoMapper.selectById(userId);
		UserInfoVo userInfoVo = new UserInfoVo(userInfo.getNickname(), userInfo.getAvatarUrl());
		return userInfoVo;
	}
}
